﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Common.Tools
{
    [Serializable]
    public class MailInfo
    {
        public string acc { get; set; }
        public string pwd { get; set; }
        public string content { get; set; }

        public MailInfo(string a, string p, string c)
        {
            acc = a;
            pwd = p;
            content = c;
        }
    }

    public class UploadHelper
    {
        #region 属性
        public string Boundary
        {
            get
            {
                string contentType = ContentType;
                string[] ctArray = contentType.Split(';');
                if (ctArray[0].Trim().ToLower() == "multipart/form-data")
                {
                    string[] bArray = ctArray[1].Split('=');
                    return "--" + bArray[1];
                }
                return null;
            }
        }

        public string ContentType
        {
            get
            {
                if (HttpContext.Current == null)
                {
                    return "multipart/form-data; boundary=---------------------------7d5b915500cee";
                }
                return HttpContext.Current.Request.ContentType;
            }
        }
        #endregion

        public byte[] GetSerializeBytes(MailInfo data)
        {
            var bs = new BufferedStream();
            bs.WriteObject(data);
            return bs.ToArray();
        }

        /// <summary>
        /// 发送邮件POST
        /// </summary>
        /// <param name="mail">发送邮箱账号</param>
        /// <param name="acc">账号</param>
        /// <param name="pwd">密码</param>
        /// <param name="content">邮件内容</param>
        /// <param name="url"></param>
        /// <returns></returns>
        public bool SendMail(string mail, string acc, string pwd, string content, string url)
        {
            try
            {
                //var mailInfo = new MailInfo(acc, pwd, content);
                // 创建一个新的 WebClient 实例.  
                //var data = Encoding.UTF8.GetString(GetSerializeBytes(mailInfo));
                //var data = Encoding.UTF8.GetBytes(content);
                var myWebClient = new WebClient();
                string text = HttpUtility.UrlEncode(content);
                string postData = string.Format("acc={0}&pwd={1}&content={2}&mail={3}", acc, pwd, text, mail);
                // 注意这种拼字符串的ContentType  
                myWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
                // 转化成二进制数组  
                byte[] byteArray = Encoding.ASCII.GetBytes(postData);
                // 上传数据，并获取返回的二进制数据.  
                byte[] responseBytes = myWebClient.UploadData(url, "POST", byteArray);
                var s = Encoding.UTF8.GetString(responseBytes);
                var job = (JObject)JsonConvert.DeserializeObject(s);
                var value = job.GetValue("status");
                if (value == null || (int)value != 1)
                {
                    return false;
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public bool SendMailNew(string mail, string acc, string pwd, string title, string content, string url)
        {
            try
            {
                //var mailInfo = new MailInfo(acc, pwd, content);
                // 创建一个新的 WebClient 实例.  
                //var data = Encoding.UTF8.GetString(GetSerializeBytes(mailInfo));
                //var data = Encoding.UTF8.GetBytes(content);
                var myWebClient = new WebClient();
                string text = HttpUtility.UrlEncode(content);
                title = HttpUtility.UrlEncode(title);
                string postData = string.Format("acc={0}&pwd={1}&content={2}&mail={3}&title={4}", acc, pwd, text, mail, title);
                // 注意这种拼字符串的ContentType  
                myWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
                // 转化成二进制数组  
                byte[] byteArray = Encoding.ASCII.GetBytes(postData);
                // 上传数据，并获取返回的二进制数据.  
                byte[] responseBytes = myWebClient.UploadData(url, "POST", byteArray);
                var s = Encoding.UTF8.GetString(responseBytes);
                var job = (JObject)JsonConvert.DeserializeObject(s);
                var value = job.GetValue("status");
                if (value == null || (int)value != 1)
                {
                    return false;
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 发送邮件POST
        /// </summary>
        /// <param name="mail">邮箱账号</param>
        /// <param name="acc">账号</param>
        /// <param name="pwd">密码</param>
        /// <param name="content">邮件内容</param>
        /// <param name="url"></param>
        /// <param name="filepath">附件文件路径</param>
        /// <returns></returns>
        public bool SendMail(string mail, string acc, string pwd, string content, string url, string filepath)
        {
            // 生成需要上传的二进制数组
            // 所有表单数据         
            var bytesArray = new ArrayList
            {
                CreateFieldData("acc", acc),// 普通表单
                CreateFieldData("pwd", pwd),// 普通表单
                CreateFieldData("content", content),// 普通表单  
                CreateFieldData("mail", mail),// 普通表单
            };

            if (!string.IsNullOrEmpty(filepath))
            {
                byte[] fileBytes = GetFileBytes(filepath);
                if (fileBytes != null && fileBytes.LongLength < 3 * 1024 * 1024)//附件最大发送3MB
                {
                    string filename = filepath.Substring(filepath.LastIndexOf('\\') + 1);
                    const string contentType = "application/octet-stream";
                    bytesArray.Add(CreateFieldData("FileData", filename, contentType, fileBytes)); // 文件表单
                }
            }
            // 合成所有表单并生成二进制数组,并发送
            return SendMail(JoinBytes(bytesArray), url);
        }

        private bool SendMail(byte[] sendBytes, string url)
        {
            if (sendBytes == null || sendBytes.Length <= 0) return false;

            if (string.IsNullOrEmpty(url)) return false;
            // 返回的内容
            byte[] responseBytes;
            // 上传到指定Url
            bool uploaded = UploadData(url, sendBytes, out responseBytes);
            if (!uploaded) return false;
            var s = Encoding.UTF8.GetString(responseBytes);
            var job = (JObject)JsonConvert.DeserializeObject(s);
            var value = job.GetValue("status");
            if (value == null || (int)value != 1)
            {
                return false;
            }
            return true;
        }

        public byte[] GetFileBytes(string filepath)
        {
            // 检查文件是否存在
            if (!File.Exists(filepath)) return null;
            // 读文件流
            var fs = new FileStream(filepath, FileMode.Open,
                FileAccess.Read, FileShare.Read);
            var fileBytes = new byte[fs.Length];
            fs.Read(fileBytes, 0, Convert.ToInt32(fs.Length));
            fs.Close();
            return fileBytes;
        }

        public bool UploadFile(string filepath, string url)
        {
            byte[] fileBytes = GetFileBytes(filepath);
            if (fileBytes == null) return false;


            // 生成需要上传的二进制数组
            // 所有表单数据
            string filename = filepath.Substring(filepath.LastIndexOf('\\') + 1);
            const string contentType = "application/octet-stream";
            var bytesArray = new ArrayList
            {
                CreateFieldData("FileData", filename, contentType, fileBytes)// 文件表单
            };
            // 合成所有表单并生成二进制数组
            var bytes = JoinBytes(bytesArray);
            if (bytes == null || bytes.Length <= 0) return false;
            if (string.IsNullOrEmpty(url)) return false;
            // 返回的内容
            byte[] responseBytes;
            // 上传到指定Url
            bool uploaded = UploadData(url, bytes, out responseBytes);
            if (!uploaded) return false;
            return true;
        }

        /// <summary>
        /// 拼接所有的二进制数组为一个数组
        /// </summary>
        /// <param name="byteArrays">数组</param>
        /// <returns></returns>
        /// <remarks>加上结束边界</remarks>
        public byte[] JoinBytes(ArrayList byteArrays)
        {
            int readLength = 0;

            // 加上结束边界
            string endBoundary = Boundary + "--\r\n"; //结束边界
            byte[] endBoundaryBytes = Encoding.UTF8.GetBytes(endBoundary);
            byteArrays.Add(endBoundaryBytes);

            int length = byteArrays.Cast<byte[]>().Sum(b => b.Length);
            var bytes = new byte[length];

            // 遍历复制
            //
            foreach (byte[] b in byteArrays)
            {
                b.CopyTo(bytes, readLength);
                readLength += b.Length;
            }

            return bytes;
        }

        public bool UploadData(string uploadUrl, byte[] bytes, out byte[] responseBytes)
        {
            var webClient = new WebClient();
            webClient.Headers.Add("Content-Type", ContentType);

            try
            {
                responseBytes = webClient.UploadData(uploadUrl, bytes);
                return true;
            }
            catch (WebException ex)
            {
                //WriteLog("上传文件 : " + ex.Message, FileSystem.ErrorGrade.EG_1);
                responseBytes = null;
            }
            return false;
        }

        /// <summary>
        /// 获取普通表单区域二进制数组
        /// </summary>
        /// <param name="fieldName">表单名</param>
        /// <param name="fieldValue">表单值</param>
        /// <returns></returns>
        /// <remarks>
        /// -----------------------------7d52ee27210a3c\r\nContent-Disposition: form-data; name=\"表单名\"\r\n\r\n表单值\r\n
        /// </remarks>
        public byte[] CreateFieldData(string fieldName, string fieldValue)
        {
            string textTemplate = Boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n";
            string text = String.Format(textTemplate, fieldName, fieldValue);
            byte[] bytes = Encoding.UTF8.GetBytes(text);
            return bytes;
        }

        /// <summary>
        /// 获取文件上传表单区域二进制数组
        /// </summary>
        /// <param name="fieldName">表单名</param>
        /// <param name="filename">文件名</param>
        /// <param name="contentType">文件类型</param>
        /// <param name="fileBytes"></param>
        /// <returns>二进制数组</returns>
        public byte[] CreateFieldData(string fieldName, string filename, string contentType, byte[] fileBytes)
        {
            const string end = "\r\n";
            string textTemplate = Boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";

            // 头数据
            string data = String.Format(textTemplate, fieldName, filename, contentType);
            byte[] bytes = Encoding.UTF8.GetBytes(data);



            // 尾数据
            byte[] endBytes = Encoding.UTF8.GetBytes(end);

            // 合成后的数组
            var fieldData = new byte[bytes.Length + fileBytes.Length + endBytes.Length];

            bytes.CopyTo(fieldData, 0); // 头数据
            fileBytes.CopyTo(fieldData, bytes.Length); // 文件的二进制数据
            endBytes.CopyTo(fieldData, bytes.Length + fileBytes.Length); // \r\n

            return fieldData;
        }
    }
}
